using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Terra.Core.Configuration;
using Terra.Core.Infrastructure.Security;
using System.Linq.Expressions;
using Terra.Data.Entities;
using Terra.Data.Entities.Identity;
using System.Reflection;
using Terra.Data.Entities.Logging;
using Terra.Data.SeedData;

namespace Terra.Data.Context;

/// <summary>
/// Terra数据库上下文
/// </summary>
public class TerraDbContext : DbContext
{
    private readonly ProjectSettings _settings;
    private readonly ICurrentUser _currentUser;

    /// <summary>
    /// 用户
    /// </summary>
    public DbSet<User> Users { get; set; } = null!;

    /// <summary>
    /// 角色
    /// </summary>
    public DbSet<Role> Roles { get; set; } = null!;

    /// <summary>
    /// 菜单
    /// </summary>
    public DbSet<Menu> Menus { get; set; }

    /// <summary>
    /// 用户角色关系
    /// </summary>
    public DbSet<UserRole> UserRoles { get; set; } = null!;

    /// <summary>
    /// 用户声明
    /// </summary>
    public DbSet<UserClaim> UserClaims { get; set; } = null!;

    /// <summary>
    /// 刷新令牌表
    /// </summary>
    public DbSet<RefreshToken> RefreshTokens { get; set; }

    /// <summary>
    /// 登录日志表
    /// </summary>
    public DbSet<LoginLog> LoginLogs { get; set; }

    /// <summary>
    /// 密码重置令牌实体
    /// </summary>
    public DbSet<PasswordResetToken> PasswordResetTokens { get; set; }

    /// <summary>
    /// 异常日志
    /// </summary>
    public DbSet<ExceptionLog> ExceptionLogs { get; set; }

    /// <summary>
    /// 部门信息
    /// </summary>
    public DbSet<Dept> Depts { get; set; }

    /// <summary>
    /// 角色权限关联
    /// </summary>
    public DbSet<RolePermission> RolePermissions { get; set; }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="options">配置选项</param>
    /// <param name="settings">项目配置</param>
    /// <param name="currentUser">当前用户服务</param>
    public TerraDbContext(
        DbContextOptions<TerraDbContext> options,
        ProjectSettings settings,
        ICurrentUser currentUser)
        : base(options)
    {
        _settings = settings;
        _currentUser = currentUser;
    }

    /// <summary>
    /// 配置模型
    /// </summary>
    /// <param name="modelBuilder">模型构建器</param>
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 应用当前程序集中的所有实体配置
        modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());




        // 设置表前缀
        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            entityType.SetTableName($"{_settings.TablePrefix}{entityType.GetTableName()}");
        }

        // 添加全局软删除过滤器
        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            if (typeof(ISoftDelete).IsAssignableFrom(entityType.ClrType))
            {
                var parameter = Expression.Parameter(entityType.ClrType, "e");
                var property = Expression.Property(parameter, nameof(ISoftDelete.IsDeleted));
                var falseConstant = Expression.Constant(false);
                var lambda = Expression.Lambda(Expression.Equal(property, falseConstant), parameter);

                modelBuilder.Entity(entityType.ClrType).HasQueryFilter(lambda);
            }
        }

        // 配置全局过滤器
        modelBuilder.Entity<ExceptionLog>()
            .HasQueryFilter(e => !e.IsDeleted);

        // 应用种子数据
        SeedDataManager.ApplySeedData(modelBuilder);

        base.OnModelCreating(modelBuilder);
    }

    /// <summary>
    /// 保存更改
    /// </summary>
    /// <returns>影响的行数</returns>
    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        var entries = ChangeTracker.Entries<IAuditEntity>().ToList();
        var currentUser = _currentUser.Id ?? null;

        foreach (var entry in entries)
        {
            switch (entry.State)
            {
                case EntityState.Added:
                    if (entry.Entity is EntityBase<Guid> guidEntity)
                    {
                        guidEntity.Id = guidEntity.Id == Guid.Empty ? Guid.NewGuid() : guidEntity.Id;
                    }
                    entry.Entity.CreatedTime = DateTime.UtcNow;
                    entry.Entity.CreatedBy = currentUser;
                    break;

                case EntityState.Modified:
                    if (entry.Entity is ISoftDelete softDelete && softDelete.IsDeleted)
                    {
                        softDelete.DeletedTime = DateTime.UtcNow;
                        softDelete.DeletedBy = currentUser;
                    }
                    else
                    {
                        entry.Entity.LastModifiedTime = DateTime.UtcNow;
                        entry.Entity.LastModifiedBy = currentUser;
                    }
                    break;
            }
        }

        return await base.SaveChangesAsync(cancellationToken);
    }
}